﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Dx.Common.Common
{
    public class ShotCacheHelper
    {
        /// <summary>
        /// web快照磁盘存放地址
        /// </summary>
        private static string shotPath = ParametersBaseHelper.BaseDirectoryPath + "Cache\\ShotCache";

        /// <summary>
        /// 异步从磁盘读取web快照
        /// </summary>
        /// <param name="DicWebShot"></param>
        public static ConcurrentDictionary<string, Bitmap> ReadCache()
        {
            ConcurrentDictionary<string, Bitmap> DicWebShot = new ConcurrentDictionary<string, Bitmap>();
            Task.Run(() =>
            {
                if (!File.Exists(shotPath))
                {
                    return;
                }
                try
                {
                    using (FileStream fStm = new FileStream(shotPath, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        int readBt = 0;
                        while (readBt > -1)
                        {
                            readBt = fStm.ReadByte();//长度的长度
                            if (readBt < 0) { break; }
                            byte[] buffer = new byte[readBt];
                            fStm.Read(buffer, 0, buffer.Length);
                            string lenStr = Encoding.UTF8.GetString(buffer);//长度
                            int len;
                            if (int.TryParse(lenStr, out len))
                            {
                                byte[] bufferVal = new byte[len];
                                fStm.Read(bufferVal, 0, bufferVal.Length);
                                string url = DecodeBytes(readBt, bufferVal); //Encoding.UTF8.GetString(bufferVal);

                                //读流
                                readBt = fStm.ReadByte();//长度的长度
                                buffer = new byte[readBt];
                                fStm.Read(buffer, 0, buffer.Length);
                                lenStr = Encoding.UTF8.GetString(buffer);//长度
                                if (int.TryParse(lenStr, out len))
                                {
                                    bufferVal = new byte[len];
                                    fStm.Read(bufferVal, 0, bufferVal.Length);
                                    using (MemoryStream mStm = new MemoryStream(bufferVal))
                                    {
                                        Bitmap bitmap = new Bitmap(mStm);
                                        DicWebShot.TryAdd(url, bitmap);
                                    }
                                }
                            }
                        }
                        fStm.Close();
                    }
                }
                catch { }
            });
            //Task.Factory.StartNew(() =>
            //{
            //    if (!File.Exists(shotPath))
            //    {
            //        return;
            //    }
            //    try
            //    {
            //        using (FileStream fStm = new FileStream(shotPath, FileMode.Open, FileAccess.Read, FileShare.Read))
            //        {
            //            int readBt = 0;
            //            while (readBt > -1)
            //            {
            //                readBt = fStm.ReadByte();//长度的长度
            //                if (readBt < 0) { break; }
            //                byte[] buffer = new byte[readBt];
            //                fStm.Read(buffer, 0, buffer.Length);
            //                string lenStr = Encoding.UTF8.GetString(buffer);//长度
            //                int len;
            //                if (int.TryParse(lenStr, out len))
            //                {
            //                    byte[] bufferVal = new byte[len];
            //                    fStm.Read(bufferVal, 0, bufferVal.Length);
            //                    string url = DecodeBytes(readBt, bufferVal); //Encoding.UTF8.GetString(bufferVal);

            //                    //读流
            //                    readBt = fStm.ReadByte();//长度的长度
            //                    buffer = new byte[readBt];
            //                    fStm.Read(buffer, 0, buffer.Length);
            //                    lenStr = Encoding.UTF8.GetString(buffer);//长度
            //                    if (int.TryParse(lenStr, out len))
            //                    {
            //                        bufferVal = new byte[len];
            //                        fStm.Read(bufferVal, 0, bufferVal.Length);
            //                        using (MemoryStream mStm = new MemoryStream(bufferVal))
            //                        {
            //                            Bitmap bitmap = new Bitmap(mStm);
            //                            DicWebShot.TryAdd(url, bitmap);
            //                        }
            //                    }
            //                }
            //            }
            //            fStm.Close();
            //        }
            //    }
            //    catch { }
            //});
            return DicWebShot;
        }
        /// <summary>
        /// 把web快照写入磁盘
        /// </summary>
        /// <param name="DicWebShot"></param>
        public static void WriteCache(ConcurrentDictionary<string, Bitmap> DicWebShot)
        {
            if (DicWebShot.Count > 0)
            {
                try
                {
                    if (File.Exists(shotPath))
                    {
                        File.Delete(shotPath);
                    }

                    using (FileStream fStm = new FileStream(shotPath, FileMode.Create, FileAccess.Write, FileShare.Write))
                    {
                        foreach (var kv in DicWebShot)
                        {
                            WriteLenToStream(fStm, Encoding.UTF8.GetBytes(kv.Key).Length.ToString().Length);//url长度的长度
                            WriteStrToStream(fStm, kv.Key.Length.ToString());//url的长度。认为都英文字母，1个字母1个字节
                                                                             //WriteStrToStream(fStm, kv.Key);//url
                            byte[] urlBts = EncodeStr(kv.Key);
                            fStm.Write(urlBts, 0, urlBts.Length);

                            using (MemoryStream kvStm = new MemoryStream())
                            {
                                kv.Value.Save(kvStm, ImageFormat.Png);
                                WriteLenToStream(fStm, kvStm.Length.ToString().Length);//流的长度的长度
                                WriteStrToStream(fStm, kvStm.Length.ToString());//流的长度
                                                                                //写入文件
                                kvStm.Seek(0, SeekOrigin.Begin);
                                kvStm.WriteTo(fStm);
                            }
                            kv.Value.Dispose();
                        }
                        fStm.Close();
                    }
                }
                catch { }
            }
        }
        private static void WriteLenToStream(Stream stm, int len)
        {
            stm.WriteByte((byte)len);
        }
        /// <summary>
        /// 把指定字符串写入流
        /// </summary>
        /// <param name="stm">要写入的流</param>
        /// <param name="str">要写入的字符串</param>
        private static void WriteStrToStream(Stream stm, string str)
        {
            byte[] bt = Encoding.UTF8.GetBytes(str);
            stm.Write(bt, 0, bt.Length);
        }
        /// <summary>
        /// 加密字符串，仅支持简单的单字节128以下的字符
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        private static byte[] EncodeStr(string str)
        {
            int len = str.Length.ToString().Length;//长度的长度
            int start = (len % 2 == 0 ? 108 : 109) + len;
            byte[] bts = Encoding.UTF8.GetBytes(str);
            byte[] rtnBt = bts.Select(x => (byte)(x + start)).ToArray();
            return rtnBt;
        }
        /// <summary>
        /// 解密字符串，仅支持简单的单字节128以下的字符串
        /// </summary>
        /// <param name="len">字符串的长度的位数（长度），注意不是字符串长度</param>
        /// <param name="bt">要解密的字节数组</param>
        /// <returns></returns>
        private static string DecodeBytes(int len, byte[] bt)
        {
            int start = (len % 2 == 0 ? 108 : 109) + len;
            byte[] deBts = bt.Select(x => (byte)(x - start)).ToArray();
            string rtnStr = Encoding.ASCII.GetString(deBts);
            return rtnStr;
        }
    }
}
